/**  
* Copyright (c) 2009, Noel Lynch All rights reserved. Redistribution and use  
* in source and binary forms, with or without modification, are permitted  
* provided that the following conditions are met: Redistributions of source  
* code must retain the above copyright notice, this list of conditions and the  
* following disclaimer. Redistributions in binary form must reproduce the above  
* copyright notice, this list of conditions and the following disclaimer in the  
* documentation and/or other materials provided with the distribution. Neither  
* the name of Noel Lynch nor the names of contributors may be used to  
* endorse or promote products derived from this software without specific prior  
* written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A  
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR  
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
*/
// created by noellynch
// Sep 2, 2009

package com.sceneworker.app.tests;

import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.app.SimpleGame;
import com.jme.image.Image;
import com.jme.image.Texture;
import com.jme.input.FirstPersonHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.light.DirectionalLight;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Node;
import com.jme.scene.SharedMesh;
import com.jme.scene.Spatial;
import com.jme.scene.TriMesh;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.GLSLShaderObjectsState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.TextureManager;
import com.jme.util.geom.TangentBinormalGenerator;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.SimpleResourceLocator;
import com.jme.util.shader.ShaderVariable;
import com.jmex.model.collada.ColladaImporter;
import com.sceneworker.app.globals.SceneWorkerGlobals;

/**
 * TestNormalmap
 */
public class TestNormalMapAttrs extends SimpleGame {
    private static final Logger logger = Logger.getLogger(TestNormalMapAttrs.class
            .getName());
    
    private Vector3f lightDir = new Vector3f();
    private GLSLShaderObjectsState so;
    private String currentShaderStr = SceneWorkerGlobals.SCENEWORKER_SHADER_DIR + "normalMapNoSpecularWithAttrs/normalMapNoSpecularWithAttrs";

    public static void main(String[] args) {
    	TestNormalMapAttrs app = new TestNormalMapAttrs();
        app.setConfigShowMode(ConfigShowMode.AlwaysShow);
        app.start();
    }

    protected void simpleUpdate() {
        if (KeyBindingManager.getKeyBindingManager().isValidCommand(
                "reloadShader", false)) {
            reloadShader();
        }

        float spinValX = FastMath.sin(timer.getTimeInSeconds() * 2.0f);
        float spinValY = FastMath.cos(timer.getTimeInSeconds() * 2.0f);
        lightDir.set(spinValX, spinValY, -1.0f).normalizeLocal();
    }

    public void reloadShader() {
        GLSLShaderObjectsState testShader = DisplaySystem.getDisplaySystem()
                .getRenderer().createGLSLShaderObjectsState();
        try {
            testShader.load(TestNormalMapAttrs.class.getClassLoader()
                    .getResource(currentShaderStr + ".vert"),
                    TestNormalMapAttrs.class.getClassLoader().getResource(
                            currentShaderStr + ".frag"));
            testShader.apply();
            DisplaySystem.getDisplaySystem().getRenderer().checkCardError();
        } catch (JmeException e) {
            logger.log(Level.WARNING, "Failed to reload shader", e);
            return;
        }

        so.load(TestNormalMapAttrs.class.getClassLoader().getResource(
                currentShaderStr + ".vert"), TestNormalMapAttrs.class
                .getClassLoader().getResource(currentShaderStr + ".frag"));

        so.setUniform("baseMap", 0);
        so.setUniform("normalMap", 1);
        so.setUniform("specularMap", 2);

        logger.info("Shader reloaded...");
    }

    protected void simpleInitGame() {
        KeyBindingManager.getKeyBindingManager().set("reloadShader",
                KeyInput.KEY_F);

        // Our model is Z up so orient the camera properly.
        cam.setAxes(new Vector3f(-1, 0, 0), new Vector3f(0, 0, 1),
                new Vector3f(0, 1, 0));
        cam.setLocation(new Vector3f(0, -100, 0));

        // Create a directional light
        DirectionalLight dr = new DirectionalLight();
        dr.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        dr.setAmbient(new ColorRGBA(0.2f, 0.2f, 0.2f, 1.0f));
        dr.setSpecular(new ColorRGBA(0.7f, 0.7f, 0.7f, 1.0f));
        dr.setDirection(lightDir);
        dr.setEnabled(true);

        lightState.detachAll();
        lightState.attach(dr);

        Box box = new Box("box", new Vector3f(), 1, 1, 1);
        rootNode.attachChild(box);

        so = display.getRenderer().createGLSLShaderObjectsState();

        // Check is GLSL is supported on current hardware.
        if (!GLSLShaderObjectsState.isSupported()) {
            logger.severe("Your graphics card does not support GLSL programs, and thus cannot run this test.");
            quit();
        }

        reloadShader();

        TextureState ts = display.getRenderer().createTextureState();

        // Base texture
        Texture baseMap = TextureManager.loadTexture(TestNormalMapAttrs.class
                .getClassLoader().getResource(
                "jmetest/data/images/Fieldstone.jpg"),
                Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
        baseMap.setWrap(Texture.WrapMode.Repeat);
        ts.setTexture(baseMap, 0);

        // Normal map
        Texture normalMap = TextureManager.loadTexture(TestNormalMapAttrs.class
                .getClassLoader().getResource(
                "jmetest/data/images/FieldstoneNormal.jpg"),
                Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear,
                Image.Format.GuessNoCompression, 0.0f, true);
        normalMap.setWrap(Texture.WrapMode.Repeat);
        ts.setTexture(normalMap, 1);

        // Specular map
        Texture specMap = TextureManager.loadTexture(TestNormalMapAttrs.class
                .getClassLoader().getResource(
                "jmetest/data/images/FieldstoneSpec.jpg"),
                Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
        specMap.setWrap(Texture.WrapMode.Repeat);
        ts.setTexture(specMap, 2);

        try {
            ResourceLocatorTool.addResourceLocator(
                    ResourceLocatorTool.TYPE_TEXTURE,
                    new SimpleResourceLocator(TestNormalMapAttrs.class
                            .getClassLoader().getResource(
                                    "jmetest/data/model/collada/")));
        } catch (URISyntaxException e1) {
            logger.warning("Unable to add texture directory to RLT: "
                    + e1.toString());
        }
        
        Sphere		lcl_sp = new Sphere("Sphere", 30, 30, 10);
        TangentBinormalGenerator.generate(lcl_sp);
        
        // Test materialstate (should be set through the import anyway)
        MaterialState ms = display.getRenderer().createMaterialState();
        ms.setColorMaterial(MaterialState.ColorMaterial.AmbientAndDiffuse);
        ms.setAmbient(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        ms.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        ms.setSpecular(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        ms.setShininess(25.0f);

        // Set all states on model
        lcl_sp.setRenderState(ts);
        lcl_sp.setRenderState(so);
        lcl_sp.setRenderState(ms);
        
        so.setAttributePointer("modelTangent", 3, true, 0, lcl_sp.getTangentBuffer());
        so.setAttributePointer("modelBinormal", 3, true, 0, lcl_sp.getBinormalBuffer());
        
        for(ShaderVariable lcl_v : so.getShaderAttributes()) {
        	System.out.println(lcl_v.name + " " + lcl_v.variableID);
        }
        
        rootNode.attachChild(lcl_sp);

        rootNode.updateGeometricState(0, true);

         input = new FirstPersonHandler( cam, 80, 1 );
    }
}